﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Web.UI.WebControls;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.WebControls;

namespace Examples.CAMLFilter
{

    /// <summary>
    /// Класс пикера, который берет данные для Lookup-фильтра из списка
    /// </summary>
    class ListItemPicker : EntityEditorWithPicker
    {

        public ListItemPickerData PickerData
        {
            get
            {
                if (_pickerData == null && String.IsNullOrEmpty(CustomProperty) == false)
                {
                    byte[] buffer = Convert.FromBase64String(CustomProperty);
                    using (MemoryStream stream = new MemoryStream(buffer))
                    {
                        BinaryFormatter formatter = new BinaryFormatter();
                        _pickerData = (ListItemPickerData)formatter.Deserialize(stream);
                    }
                }
                return _pickerData;
            }
            set
            {
                if (value != null)
                {
                    _pickerData = value;
                    using (MemoryStream stream = new MemoryStream())
                    {
                        BinaryFormatter formatter = new BinaryFormatter();
                        formatter.Serialize(stream, value);
                        CustomProperty = Convert.ToBase64String(stream.ToArray());
                    }
                }
                else
                {
                    CustomProperty = null;
                    _pickerData = null;
                }
            }
        }
        ListItemPickerData _pickerData = null;

        public SPField LookupField
        {
            get
            {
                if (_lookupField == null)
                {
                    _lookupField = List.Fields.GetFieldByInternalName(PickerData.FieldName);
                }
                return _lookupField;
            }
        }
        SPField _lookupField = null;

        public SPWeb Web
        {
            get
            {
                if (_web == null)
                {
                    SPSite site = SPContext.Current.Site;
                    _web = site.OpenWeb(PickerData.WebID);
                }
                return _web;
            }
        }
        SPWeb _web = null;

        public SPList List
        {
            get
            {
                if (_list == null)
                {
                    _list = Web.Lists[PickerData.ListID];
                }
                return _list;
            }
        }
        SPList _list = null;

        /// <summary>
        /// Ресолвит все энтити и возвращает true, если это удалось
        /// </summary>
        /// <returns></returns>
        public Boolean ResolveAllEntities()
        {
            Boolean res = true;
            for (int i = 0; i < Entities.Count; i++)
            if (Entities[i] is PickerEntity)
            {
                if (!((PickerEntity)Entities[i]).IsResolved)
                {
                    PickerEntity entity = this.ValidateEntity((PickerEntity)Entities[i]);
                    if (entity.IsResolved)
                        Entities[i] = entity;
                    else
                        res = false;
                    
                }
            }
            else
                res = false;

            return res;
        }

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            PickerDialogType = typeof(ListItemPickerDialog);
            AllowTypeIn = true;
        }

        // Called for the 'Validate' button instead of 'Browse'
        // Also called upon OK button click
        public override PickerEntity ValidateEntity(PickerEntity needsValidation)
        {
            // The PickerEntity is unresolved when the user doesn't 
            // operate the picker dialog, but presses the 'Validate' button
            if (needsValidation.IsResolved)
            {
                return needsValidation; // resolved
            }

            // Ищем
            if (!String.IsNullOrEmpty(needsValidation.Key))
            {

                // Проверяем, а не ID ли у нас в коде сидит
                int id = -1;
                if (Int32.TryParse(needsValidation.Key, out id) && id > 0)
                {
                    SPListItem item = null;
                    try 
                    {
                        item = List.GetItemById(id);
                    }
                    catch (Exception) {}
                    if (item != null)
                    {
                        needsValidation = new PickerEntity();
                        needsValidation.Key = item.ID.ToString();
                        needsValidation.DisplayText = item[LookupField.Id].ToString();
                        needsValidation.IsResolved = true;
                        return needsValidation;
                    }
                }



                SPQuery q = new SPQuery();


                q.Query = String.Format(@"<Where><Contains><FieldRef Name='{0}'/><Value Type='{1}'>{2}</Value></Contains></Where>",
                    LookupField.InternalName, LookupField.Type, needsValidation.Key);

                q.ViewAttributes = "Scope='Recursive'";
                q.RowLimit = 5;

                SPListItemCollection items = List.GetItems(q);
                switch (items.Count)
                {
                    case 0:
                        needsValidation.Description = SPUtility.GetLocalizedString("$Resources:PCNoMatches", "Examples.CAMLFilter", PickerData.Locale);
                        break;
                    case 1:

                        needsValidation = new PickerEntity();
                        needsValidation.Key = items[0].ID.ToString();
                        needsValidation.DisplayText = items[0][LookupField.Id].ToString();
                        needsValidation.IsResolved = true;

                        // Нашли - уходим довольные
                        return needsValidation;


                    default:

                        break;

                }
            }
            return needsValidation;
        }

        protected override PickerEntity[] ResolveErrorBySearch(string unresolvedText)
        {
            List<PickerEntity> resolvedItems = null;

            SPQuery q = new SPQuery();
            q.Query = String.Format(
               @"<Where>
                    <Contains>
                        <FieldRef Name='{0}'/>
                        <Value Type='{1}'>{2}</Value>
                    </Contains>
                </Where>
                <OrderBy>
                    <FieldRef Name='{0}' Ascending='True' />
                </OrderBy>",
               LookupField.InternalName, LookupField.Type, unresolvedText);
            q.ViewAttributes = "Scope='Recursive'";

            SPListItemCollection _currentMatches = List.GetItems(q);

            if (String.IsNullOrEmpty(unresolvedText) == false &&
                _currentMatches.Count > 0)
            {
                resolvedItems = new List<PickerEntity>();
                foreach (SPListItem listItem in _currentMatches)
                {
                    PickerEntity entity = new PickerEntity();
                    entity.Key = listItem.ID.ToString();
                    entity.DisplayText = listItem[LookupField.Id].ToString();
                    entity.IsResolved = true;
                    resolvedItems.Add(entity);
                }
            }

            return resolvedItems != null ?
                resolvedItems.ToArray() : null;
        }

        public override void Dispose()
        {
            if (_web != null)
            {
                _web.Dispose();
            }
            base.Dispose();
        }

    }

    /// <summary>
    /// Класс диалога для ListItemPicker
    /// </summary>
    class ListItemPickerDialog : PickerDialog
    {
        internal ListItemPicker ListItemPicker
        {
            get { return (ListItemPicker)base.EditorControl; }
        }

        public ListItemPickerDialog()
            : base(
                new ListItemPickerQueryControl(),
                new TableResultControl(),
                new ListItemPicker())
        {
        }


        protected override void OnLoad(EventArgs e)
        {
            DialogTitle = SPUtility.GetLocalizedString("$Resources:PCTitle", "Examples.CAMLFilter", ListItemPicker.PickerData.Locale);
            Description = SPUtility.GetLocalizedString("$Resources:PCDescription", "Examples.CAMLFilter", ListItemPicker.PickerData.Locale);
            base.OnLoad(e);
        }


    }

    /// <summary>
    /// Вспомогательный класс для ListItemPicker
    /// </summary>
    class ListItemPickerQueryControl : SimpleQueryControl
    {

        public SPField LookupField
        {
            get
            {
                if (_lookupField == null)
                {
                    _lookupField = List.Fields.GetFieldByInternalName(ListItemPickerDialog.ListItemPicker.PickerData.FieldName);
                }
                return _lookupField;
            }
        }
        SPField _lookupField = null;

        public SPWeb Web
        {
            get
            {
                if (_web == null)
                {
                    SPSite site = SPContext.Current.Site;
                    _web = site.OpenWeb(ListItemPickerDialog.ListItemPicker.PickerData.WebID);
                }
                return _web;
            }
        }
        SPWeb _web = null;

        public SPList List
        {
            get
            {
                if (_list == null)
                {
                    _list = Web.Lists[ListItemPickerDialog.ListItemPicker.PickerData.ListID];
                }
                return _list;
            }
        }
        SPList _list = null;


        const string KeyColumnName = "Key__";
        const string ValueColumnName = "Val__";

        ListItemPickerDialog ListItemPickerDialog
        {
            get { return (ListItemPickerDialog)PickerDialog; }
        }


        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            if (!Page.IsPostBack)
            {
                EnsureChildControls();

                // Инитим поле поиска

                mColumnList.Items.Add(new ListItem(LookupField.Title, LookupField.InternalName));

                mColumnList.SelectedValue = LookupField.InternalName;


                ArrayList columnNames = ((TableResultControl)ListItemPickerDialog.ResultControl).ColumnNames;
                columnNames.Clear();
                ArrayList columnDisplayNames = ((TableResultControl)ListItemPickerDialog.ResultControl).ColumnDisplayNames;
                columnDisplayNames.Clear();
                ArrayList columnWidths = ((TableResultControl)ListItemPickerDialog.ResultControl).ColumnWidths;
                columnWidths.Clear();

                columnNames.Add(ValueColumnName);
                columnDisplayNames.Add(LookupField.Title);
                columnWidths.Add("100%");

            }


        }


        protected override int IssueQuery(string search, string column, int pageIndex, int pageSize)
        {
            DataTable resultsTable = new DataTable();


            resultsTable.Columns.Add(KeyColumnName, typeof(int));
            resultsTable.Columns.Add(ValueColumnName, typeof(string));

            SPQuery query = new SPQuery();

            query.Query = String.Format(
                String.IsNullOrEmpty(search) ? "" :
                @"<Where>
                    <Contains>
                        <FieldRef Name='{0}'/>
                        <Value Type='{1}'>{2}</Value>
                    </Contains>
                </Where>" +
                @"<OrderBy>
                    <FieldRef Name='{0}' Ascending='True' />
                </OrderBy>",
                LookupField.InternalName, LookupField.Type, search
            );
            query.ViewAttributes = "Scope='Recursive'";

            // Query the list and build result items
            foreach (SPListItem listItem in List.GetItems(query))
            {
                DataRow row = resultsTable.NewRow();
                row[KeyColumnName] = listItem.ID.ToString();
                row[ValueColumnName] = listItem[LookupField.Id].ToString();
                resultsTable.Rows.Add(row);
            }


            PickerDialog.Results = resultsTable;
            // PickerDialog.ResultControl.PageSize = resultsTable.Rows.Count;

            return resultsTable.Rows.Count;
        }



        public override PickerEntity GetEntity(DataRow row)
        {
            SPListItem item = ListItemPickerDialog.ListItemPicker.List.GetItemById((int)row[KeyColumnName]);

            PickerEntity entity = new PickerEntity();

            entity.Key = item.ID.ToString();
            entity.DisplayText = item[LookupField.Id].ToString();
            entity.IsResolved = true;

            return entity;
        }

        public override void Dispose()
        {
            if (_web != null)
            {
                _web.Dispose();
            }
            base.Dispose();
        }

    }

    [Serializable]
    public class ListItemPickerData : ISerializable
    {
        public Guid WebID { get; private set;}
        public Guid ListID  { get; private set;}
        public String FieldName { get; private set; }
        public Boolean IsMulti { get; private set; }
        public uint Locale { get; private set; }

        public ListItemPickerData(Guid webID, Guid listID, String fieldName, Boolean isMulti, uint locale)
        {
            WebID = webID;
            ListID = listID;
            FieldName = fieldName;
            IsMulti = isMulti;
            Locale = locale;
        }

        protected ListItemPickerData(SerializationInfo info, StreamingContext context)
        {
            WebID = (Guid)info.GetValue("_WebID", typeof(Guid));
            ListID = (Guid)info.GetValue("_ListID", typeof(Guid));
            FieldName = (String)info.GetValue("_FieldName", typeof(String));
            IsMulti = (Boolean)info.GetValue("_IsMulti", typeof(Boolean));
            Locale = (uint)info.GetValue("_Locale", typeof(uint));
        }

        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("_WebID", WebID);
            info.AddValue("_ListID", ListID);
            info.AddValue("_FieldName", FieldName);
            info.AddValue("_IsMulti", IsMulti);
            info.AddValue("_Locale", Locale);
        }


    }

}
